/* STANDARD LIBRARY */
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<string>
#include<math.h>
//#include<fstream>

/* GSL LIBRARY */
#include<gsl/gsl_vector.h>
#include<gsl/gsl_multiroots.h>
#include<gsl/gsl_spline.h>

/* ADDITIONAL LIBRARY */
#include"constants.h" // constants

/* DECLATATIONS */
#ifndef DECLARATIONS_supToGSL
#define DECLARATIONS_supToGSL

void* Run(void *wsk);

/* Clock - MEASURE A TIME OF PROGRAM RINNING */
class Clock
{
private:
	time_t tStart;

public:
	Clock() { time(&tStart); }
	void print()
	{
		time_t tEnd;
		time(&tEnd);
		printf("time of running: %f\n", difftime(tEnd, tStart));
	}

	float estimateEnd(float f)
	{
		if(f<0 || f>1) { return -1; }
		time_t now;
		time(&now);
		float passed = difftime(now, tStart);
		return passed*(1/f - 1);
	}
};

/* Parameters to Multiroot Solver */
class Parameters
{
private:
	unsigned int n;
	double *p;
	Parameters() { srand((unsigned)time(0)); }

public:
	Parameters(unsigned int _n) : n(_n), p(NULL) { Parameters(); }
	Parameters(unsigned int _n, double *_p) : n(_n), p(_p) { Parameters(); }
	~Parameters() {}// if(p!=NULL) delete[] p; };

	// for definition see supToGSL.cpp file
	int set(unsigned int _n, double *_p);
	int setValue(double *_p);
	double* getPointer();
	void getCopy(double *x);
	unsigned int dim();
	void deleteP();
	int print();
	double & operator[](unsigned int el);
	const double & operator[](unsigned int el) const;
	int shake(unsigned int i);
	int interpolation(double *xSet, double **ySet, unsigned int depth, unsigned int current, double xValue, double h);
};

/* Multiroot Solver */
class MultirootSolver
{
protected:
	const size_t n; // number of equations to solve
	int status; // -1 mean that solveFor hasn't done yet
	size_t iter;
	gsl_vector *gslX0; // start point

	virtual int print() = 0; // change in future to without = 0;

public:
	MultirootSolver(unsigned int _n);
	virtual ~MultirootSolver();
	virtual int solveFor(Parameters *Par, Parameters *X0) = 0;
	virtual Parameters* getResult() = 0; // change in future to without = 0
};

/* Multiroot Solver - metod 1 - f*/
typedef int (*functionF)(const gsl_vector*, void*, gsl_vector*);

class MultirootSolverF : public MultirootSolver
{
private:
	functionF f;
	gsl_multiroot_function gslF; // set of functions to solve
	const gsl_multiroot_fsolver_type *gslT;
	gsl_multiroot_fsolver *gslS; // result there (final point)

	int print();

public:
	// for definition see supToGSL.cpp file
	MultirootSolverF(functionF _f, unsigned int _n);
	~MultirootSolverF();

	int printResult();
	int printResult(FILE *fp);
	int solveFor(Parameters *Par, Parameters *X0);
	Parameters* getResult();
};

/* Multiroot Solver - metod 2 - fdf*/
typedef int (*functionDF)(const gsl_vector*, void*, gsl_matrix*);
typedef int (*functionFDF)(const gsl_vector*, void*, gsl_vector*, gsl_matrix*);

class MultirootSolverFDF : public MultirootSolver
{
private:
	functionF f;
	functionDF df;
	functionFDF fdf;
	gsl_multiroot_function_fdf gslFDF; // set of functions to solve
	const gsl_multiroot_fdfsolver_type *gslT;
	gsl_multiroot_fdfsolver *gslS; // result there (final point)

	int print();

public:
	// for definition see supToGSL.cpp file
	MultirootSolverFDF(functionF _f, functionDF _df, functionFDF _fdf, unsigned int _n);
	~MultirootSolverFDF();

	int solveFor(Parameters *Par, Parameters *X0);
	Parameters* getResult();
};
#endif
